0%
单一职责原则
- 一个类只负责一项职责。换言之,一个类应该只有一个引起它变化的原因。
开闭原则
- 软件实体类(类、模块、函数等)应该是可以扩展的,但是不可以修改。
- 我们应该通过添加新的代码来扩展软件实体的行为,而不是修改原有的代码。
里氏替换原则
- 子类应该可以完全替换父类,并且可以在不影响程序正确性的前提下增加额外的行为。
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类可以增加自己特有的方法。
- 子类的方法重载父类的方法时,方法的前置条件(方法的输入/入参)要比父类方法的输入参数更宽松。
- 子类的方法实现父类的方法时(重写/重载货实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更加严格或者一致。
依赖倒置原则
- 高层模块不应该依赖于底层模块,它们应该都依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。
接口隔离原则
- 客户端不应该依赖它不需要的接口。
- 一个类对另一个类的依赖应该建立在最小的接口上。- 我们在定义接口的时候,一定要注意控制接口的粒度,比如下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| interface Device { String getCpu(); String getType(); String getMemory(); }
class Computer implements Device {
@Override public String getCpu() { return "i9-12900K"; }
@Override public String getType() { return "电脑"; }
@Override public String getMemory() { return "32G DDR5"; } }
class Fan implements Device {
@Override public String getCpu() { return null; }
@Override public String getType() { return "风扇"; }
@Override public String getMemory() { return null; } }
|
- 虽然我们定义了一个Device接口,但是由于此接口的粒度不够细,虽然比较契合电脑这种设备,但是不适合风扇这种设备.
- 因为风扇压根就不需要CPU和内存,所以风扇完全不需要这些方法。这时我们就必须要对其进行更细粒度的划分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| interface SmartDevice { String getCpu(); String getType(); String getMemory(); }
interface NormalDevice { String getType(); }
class Computer implements SmartDevice {
@Override public String getCpu() { return "i9-12900K"; }
@Override public String getType() { return "电脑"; }
@Override public String getMemory() { return "32G DDR5"; } }
class Fan implements NormalDevice { @Override public String getType() { return "风扇"; } }
|
合成复用原则
- 核心就是委派。
- 优先使用对象组合,而不是通过继承来达到复用的目的。
- 在一个新对象里面使用一些已有的对象,使之成为新对象的一部分,新的对象通过向这些对象的委派达到复用已有功能的目的。
- 比如A类总实现了连接数据库的功能,恰巧B类中也需要,因该是在用的时候给一个A,而不是通过继承。
- 直接继承会造成耦合度太高:
1 2 3 4 5 6 7 8 9 10 11 12
| class A { public void connectDatabase(){ System.out.println("我是连接数据库操作!"); } }
class B extends A{ public void test(){ System.out.println("我是B的方法,我也需要连接数据库!"); connectDatabase(); } }
|
- 应该:
1 2 3 4 5 6 7 8 9 10 11 12
| class A { public void connectDatabase(){ System.out.println("我是连接数据库操作!"); } }
class B { public void test(A a){ System.out.println("我是B的方法,我也需要连接数据库!"); a.connectDatabase(); } }
|
迪米特法则
- 又称最少知识原则,对程序内部数据交互的限制。
- 一个对象应该对其他对象由最少的了解。
- 例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Main { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 8080); Test test = new Test(); test.test(socket); }
static class Test {
public void test(Socket socket){ System.out.println("IP地址:"+socket.getLocalAddress()); } } }
|
- 直接提供一个Socket对象,然后再由test方法来取出IP地址。
- 但是这样显然违背了迪米特法则,实际上这里的test方法只需要一个IP地址即可,我们完全可以直接传入一个字符串,而不是整个Socket对象,我们需要保证与其他类的交互尽可能的少。
- 就像我们在餐厅吃完了饭,应该是我们自己扫码付款,而不是直接把手机交给老板来帮你操作付款。